// public/js/games/loveletter-game.js

// 动画时长配置（毫秒）
const CARD_DRAW_ANIMATION_DURATION_MS = 1000; // 动画时长：1秒
const CARD_DRAW_ANIMATION_BUFFER_MS = 100; // 缓冲时间：100ms
const CARD_DRAW_ANIMATION_TOTAL_MS = CARD_DRAW_ANIMATION_DURATION_MS + CARD_DRAW_ANIMATION_BUFFER_MS;
const CARD_DISCARD_ANIMATION_DURATION_MS = CARD_DRAW_ANIMATION_DURATION_MS;
const CARD_DISCARD_ANIMATION_BUFFER_MS = CARD_DRAW_ANIMATION_BUFFER_MS;
const CARD_DISCARD_ANIMATION_TOTAL_MS = CARD_DISCARD_ANIMATION_DURATION_MS + CARD_DISCARD_ANIMATION_BUFFER_MS;

let socket;
let roomId;
let gameState;
let playerState;
let playerInfo;
let controller;
let isGameEnded = false;
let gameLog = []; // 游戏日志数组

// 卡牌名称和描述
const CARD_INFO = {
    1: { name: '卫兵', description: '猜测一名玩家的手牌，如果猜中且该牌不是卫兵，则该玩家出局' },
    2: { name: '牧师', description: '查看一名玩家的手牌' },
    3: { name: '男爵', description: '与一名玩家比较手牌数字，数字较小的玩家出局' },
    4: { name: '侍女', description: '在下一个回合前，保护自己不受其他玩家的影响' },
    5: { name: '王子', description: '选择一名玩家（包括自己），该玩家弃掉手牌并抽取新牌' },
    6: { name: '国王', description: '与一名玩家交换手牌' },
    7: { name: '伯爵夫人', description: '如果手牌中同时有伯爵夫人和王子或国王，必须打出伯爵夫人' },
    8: { name: '公主', description: '如果弃掉公主，立即出局' }
};

const CARD_IMAGE_PATHS = {
    1: '/images/loveLetter/1.png',
    2: '/images/loveLetter/2.png',
    3: '/images/loveLetter/3.png',
    4: '/images/loveLetter/4.png',
    5: '/images/loveLetter/5.png',
    6: '/images/loveLetter/6.png',
    7: '/images/loveLetter/7.png',
    8: '/images/loveLetter/8.png'
};

const CARD_BACK_IMAGE = '/images/loveLetter/back.png';

export function init(initSocket, navigationData) {
    socket = initSocket;
    // 从navigationData获取数据，兼容不同的数据格式
    roomId = navigationData.roomId || (new URLSearchParams(window.location.search).get('roomId'));
    gameState = navigationData.state || navigationData;
    playerState = navigationData.playerState;
    playerInfo = navigationData.players;
    
    isGameEnded = false;


    // 清理之前可能存在的游戏结束弹窗和动作模态框
    cleanupModals();

    // 获取DOM元素
    const playersBoardEl = document.getElementById('players-board');

    // 初始化AbortController
    controller = new AbortController();
    const { signal } = controller;

    // 初始化游戏日志
    gameLog = [];
    addLogEntry('游戏开始！', 'system');
    discardPile = [];
    lastHandledDiscards = {};
    actionSequenceCounter = 0;
    isCardDiscardAnimating = false;
    currentTurnStartTime = Date.now(); // 初始化当前回合开始时间
    previousOpponentHands = {}; // 初始化对手手牌跟踪
    opponentCardDrawAnimating = null; // 初始化对手抽牌动画标记
    updateDiscardPileView();
    
    // 设置动画时长的 CSS 变量，供 HTML 使用
    document.documentElement.style.setProperty(
        '--card-draw-animation-duration', 
        `${CARD_DRAW_ANIMATION_DURATION_MS / 1000}s`
    );
    
    // 渲染初始状态
    renderGameBoard();
    renderGameLog();
    updateMessage('等待游戏开始...');

    // 监听Socket事件
    socket.on('game_state_updated', handleGameStateUpdated);
    socket.on('your_turn', handleYourTurn);
    socket.on('action_required', handleActionRequired);
    socket.on('card_drawn', handleCardDrawn);
    socket.on('reveal_hand', handleRevealHand);
    socket.on('game_ended', handleGameEnded);
    socket.on('error', handleError);
    
    // 监听窗口大小变化，重新渲染游戏桌面
    window.addEventListener('resize', () => {
        renderGameBoard();
    }, { signal: controller.signal });
    
    // 监听桌面点击事件，点击空白位置时取消卡牌选择
    if (playersBoardEl) {
        playersBoardEl.addEventListener('click', (e) => {
            // 检查点击的目标是否是空白位置（不是卡牌、按钮、玩家区域等可交互元素）
            const target = e.target;
            const isClickableElement = target.closest('.my-card') || 
                                     target.closest('.opponent-card') ||
                                     target.closest('.player-card-slot') ||
                                     target.closest('.deck') ||
                                     target.closest('.discard') ||
                                     target.closest('button') ||
                                     target.closest('.modal');
            
            // 如果点击的是空白位置，且有选中的卡牌，取消选择
            if (!isClickableElement && selectedCardIndex !== null) {
                selectedCardIndex = null;
                renderGameBoard();
            }
        }, { signal: controller.signal });
    }
}

let waitingForTarget = false; // 是否正在等待选择目标
let availableTargets = []; // 可用的目标列表
let waitingForGuess = false; // 是否正在等待猜测卡牌（卫兵效果）
let guessTargetPlayerId = null; // 猜测的目标玩家ID
let currentAction = null; // 当前动作类型
let selectedCardIndex = null; // 选中的卡牌索引（用于出牌确认）
let playedCardIndex = null; // 已打出的卡牌索引（用于显示透明效果）
let pendingTargetSelection = null; // 延迟的目标选择（用于等待卡牌打出后选择目标）
let stagedGuardTargetId = null; // 预先选择的卫兵目标
let stagedGuardGuessCard = null; // 预先选择的卫兵猜测卡牌
let guardAutoSubmitPending = false; // 是否等待自动提交卫兵猜测
let discardPile = [];
let isCardDiscardAnimating = false;
let actionSequenceCounter = 0;
let lastHandledDiscards = {};
let currentTurnStartTime = null; // 当前回合开始的时间戳
let previousOpponentHands = {}; // 跟踪对手之前的手牌数量，用于检测抽牌
let opponentCardDrawAnimating = null; // 正在播放抽牌动画的对手ID

function getCardImageUrl(cardValue) {
    return CARD_IMAGE_PATHS[cardValue] || CARD_BACK_IMAGE;
}

function createMyCardHtml(card, options = {}) {
    const cardInfo = CARD_INFO[card] || { name: `卡牌${card}`, description: '' };
    const {
        index = null,
        isPlayable = false,
        isSelected = false,
        isPlayed = false,
        isHidden = false,
        extraClasses = []
    } = options;

    const classes = ['my-card', ...extraClasses];
    if (isPlayable) classes.push('playable');
    if (isSelected) classes.push('selected');
    if (isPlayed) classes.push('played');
    if (isHidden) classes.push('hidden');

    const styleParts = [`background-image: url('${getCardImageUrl(card)}')`];
    const styleAttr = styleParts.length ? ` style="${styleParts.join('; ')}"` : '';
    const dataIndexAttr = index !== null ? ` data-card-index="${index}"` : '';

    return `
        <div class="${classes.join(' ')}"${dataIndexAttr} data-card="${card}"${styleAttr}>
            <div class="card-overlay">
                <div class="card-name">${cardInfo.name}</div>
                <div class="card-description">${cardInfo.description}</div>
            </div>
        </div>
    `;
}

function canDrawFromDeckNow() {
    // 直接使用 gameState.currentPlayerId 判断是否是我的回合，不依赖 playerState.isMyTurn
    if (!gameState || gameState.currentPlayerId !== socket.id) {
        return false;
    }
        
    if (isCardDrawAnimating) return false;
    if (isCardDiscardAnimating) return false;
    if (waitingForTarget || waitingForGuess) return false;
    const myHand = playerState?.hand || [];
    if (myHand.length !== 1) return false;
    const deckLength = Array.isArray(gameState.deck) ? gameState.deck.length : 0;
    return deckLength > 0;
}

function updateDeckInteraction(canDraw) {
    const deckContainerEl = document.getElementById('deck-container');
    const deckEl = document.getElementById('deck');
    const deckArrowEl = document.getElementById('deck-arrow');
    if (!deckContainerEl || !deckEl) {
        return;
    }

    // 确保在初始化阶段绑定点击事件
    if (!deckEl.dataset.clickHandlerBound) {
        if (!controller) {
            controller = new AbortController();
        }
        deckEl.addEventListener('click', handleDeckClick, { signal: controller.signal });
        deckEl.dataset.clickHandlerBound = 'true';
    }

    if (canDraw) {
        deckContainerEl.classList.add('clickable');
        deckEl.classList.add('clickable');
        if (deckArrowEl) {
            deckArrowEl.classList.add('visible');
            deckArrowEl.style.opacity = '1';
            deckArrowEl.style.visibility = 'visible';
        }
    } else {
        deckContainerEl.classList.remove('clickable');
        deckEl.classList.remove('clickable');
        if (deckArrowEl) {
            deckArrowEl.classList.remove('visible');
            deckArrowEl.style.opacity = '0';
            deckArrowEl.style.visibility = 'hidden';
        }
    }
}

function handleDeckClick() {
    if (!canDrawFromDeckNow()) {
        return;
    }
    updateDeckInteraction(false);
    playCard(0);
}

function canPlayCardNow() {
    // 直接使用 gameState.currentPlayerId 判断是否是我的回合，不依赖 playerState.isMyTurn
    if (!gameState || gameState.currentPlayerId !== socket.id) return false;
    if (isCardDrawAnimating) return false;
    if (isCardDiscardAnimating) return false;
    if (waitingForTarget || waitingForGuess) return false;
    const myHand = playerState?.hand || [];
    if (myHand.length < 2) return false;
    if (selectedCardIndex === null) return false;
    const selectedCard = myHand[selectedCardIndex];
    if (!selectedCard) return false;
    // 只有不需要选择目标的卡牌才能通过点击弃牌堆出牌
    return !getCardRequiresTarget(selectedCard);
}

function updateDiscardInteraction(canPlay) {
    const discardContainerEl = document.getElementById('discard-container');
    const discardEl = document.getElementById('discard');
    const discardArrowEl = document.getElementById('discard-arrow');
    if (!discardContainerEl || !discardEl) {
        return;
    }

    // 确保在初始化阶段绑定点击事件
    if (!discardEl.dataset.clickHandlerBound) {
        if (!controller) {
            controller = new AbortController();
        }
        discardEl.addEventListener('click', handleDiscardClick, { signal: controller.signal });
        discardEl.dataset.clickHandlerBound = 'true';
    }

    // 弃牌堆始终可以点击（用于查看历史或出牌）
    discardContainerEl.classList.add('clickable');
    discardEl.classList.add('clickable');

    // 根据是否可以出牌，显示或隐藏箭头
    if (canPlay) {
        if (discardArrowEl) {
            discardArrowEl.classList.add('visible');
            discardArrowEl.style.opacity = '1';
            discardArrowEl.style.visibility = 'visible';
        }
        // 可以出牌时，添加特殊样式
        discardEl.classList.add('playable');
    } else {
        if (discardArrowEl) {
            discardArrowEl.classList.remove('visible');
            discardArrowEl.style.opacity = '0';
            discardArrowEl.style.visibility = 'hidden';
        }
        // 不能出牌时，移除特殊样式
        discardEl.classList.remove('playable');
    }
}

function handleDiscardClick() {
    // 如果可以出牌，执行出牌逻辑
    if (canPlayCardNow() && selectedCardIndex !== null) {
        updateDiscardInteraction(false);
        playCard(selectedCardIndex);
        return;
    }
    
    // 如果不能出牌，显示已打出卡牌的模态框
    showDiscardHistoryModal();
}

function showDiscardHistoryModal() {
    // 获取当前回合的弃牌（从当前回合开始时间到现在的牌）
    const currentTurnDiscards = discardPile.filter(discard => {
        return currentTurnStartTime && discard.timestamp >= currentTurnStartTime;
    });
    
    // 如果没有当前回合的弃牌，显示所有最近的弃牌（最多10张）
    const cardsToShow = currentTurnDiscards.length > 0 
        ? currentTurnDiscards 
        : discardPile.slice(-10);
    
    // 创建模态框
    const modal = document.createElement('div');
    modal.className = 'modal discard-history-modal';
    modal.id = 'discard-history-modal';
    
    let content = `
        <div class="modal-content discard-history-content">
            <div class="modal-header">
                <h2>${currentTurnDiscards.length > 0 ? '本回合已打出的牌' : '最近打出的牌'}</h2>
                <button class="modal-close-button" type="button">×</button>
            </div>
            <div class="discard-history-list">
    `;
    
    if (cardsToShow.length === 0) {
        content += '<div class="discard-history-empty">暂无弃牌</div>';
    } else {
        cardsToShow.reverse().forEach(discard => {
            const player = playerInfo.find(p => p.id === discard.playerId);
            const cardInfo = CARD_INFO[discard.card] || { name: `卡牌${discard.card}`, description: '' };
            content += `
                <div class="discard-history-item">
                    <div class="discard-history-card" style="background-image: url('${getCardImageUrl(discard.card)}')">
                        <div class="card-overlay">
                            <div class="card-name">${cardInfo.name}</div>
                        </div>
                    </div>
                    <div class="discard-history-info">
                        <div class="discard-history-player">${player?.name || '未知玩家'}</div>
                        <div class="discard-history-card-name">${cardInfo.name} (${discard.card})</div>
                    </div>
                </div>
            `;
        });
    }
    
    content += `
            </div>
        </div>
    `;
    
    modal.innerHTML = content;
    document.body.appendChild(modal);
    
    // 添加关闭按钮事件
    const closeBtn = modal.querySelector('.modal-close-button');
    if (closeBtn) {
        closeBtn.addEventListener('click', () => {
            if (modal.parentNode) {
                modal.parentNode.removeChild(modal);
            }
        }, { signal: controller.signal });
    }
    
    // 点击模态框外部关闭
    modal.addEventListener('click', (e) => {
        if (e.target === modal) {
            if (modal.parentNode) {
                modal.parentNode.removeChild(modal);
            }
        }
    }, { signal: controller.signal });
}


function updateDiscardPileView() {
    const discardEl = document.getElementById('discard');
    if (!discardEl) return;

    if (!discardPile.length) {
        discardEl.innerHTML = '<div class="discard-empty">暂无弃牌</div>';
        return;
    }

    const top = discardPile[discardPile.length - 1];
    const cardInfo = CARD_INFO[top.card] || { name: `卡牌${top.card}`, description: '' };
    discardEl.innerHTML = `
        <div class="discard-card-face" data-player-id="${top.playerId}" style="background-image: url('${getCardImageUrl(top.card)}')">
            <div class="card-overlay">
                <div class="card-name">${cardInfo.name}</div>
            </div>
        </div>
    `;
}

function getPlayerSlotElement(playerId) {
    const boardEl = document.getElementById('players-board');
    if (!boardEl) return null;
    return boardEl.querySelector(`.player-card-slot[data-player-id="${playerId}"]`);
}

function getDiscardSourceElement(playerId) {
    const slotEl = getPlayerSlotElement(playerId);
    if (!slotEl) return null;
    if (playerId === socket.id) {
        return slotEl.querySelector('.my-card.selected') ||
            slotEl.querySelector('.my-card') || slotEl;
    }
    return slotEl.querySelector('.opponent-card') || slotEl;
}

function recordDiscardEvent(playerId, cardValue, actionSequence, options = {}) {
    if (playerId == null || typeof cardValue !== 'number') {
        return;
    }

    const lastHandled = lastHandledDiscards[playerId];
    if (lastHandled && lastHandled.actionSequence === actionSequence) {
        return;
    }

    discardPile.push({
        playerId,
        card: cardValue,
        sequence: actionSequence,
        timestamp: Date.now()
    });
    if (discardPile.length > 30) {
        discardPile = discardPile.slice(discardPile.length - 30);
    }

    lastHandledDiscards[playerId] = {
        card: cardValue,
        actionSequence,
        sourceType: options.sourceType || null
    };

    if (options.animate !== false) {
        animateCardDiscard(cardValue, playerId);
    } else {
        updateDiscardPileView();
    }
}

function animateCardDiscard(card, playerId) {
    const boardEl = document.getElementById('players-board');
    const discardEl = document.getElementById('discard');
    if (!boardEl || !discardEl) return;

    const sourceElement = getDiscardSourceElement(playerId);
    if (!sourceElement) {
        updateDiscardPileView();
        return;
    }

    const boardRect = boardEl.getBoundingClientRect();
    const sourceRect = sourceElement.getBoundingClientRect();
    const discardRect = discardEl.getBoundingClientRect();

    const startX = sourceRect.left - boardRect.left + sourceRect.width / 2;
    const startY = sourceRect.top - boardRect.top + sourceRect.height / 2;
    const targetX = discardRect.left - boardRect.left + discardRect.width / 2;
    const targetY = discardRect.top - boardRect.top + discardRect.height / 2;

    const deltaX = targetX - startX;
    const deltaY = targetY - startY;

    const myCardWidth = 140;
    const myCardHeight = 196;
    const initialScale = Math.min(
        sourceRect.width / myCardWidth,
        sourceRect.height / myCardHeight
    );
    const targetScale = Math.min(
        discardRect.width / myCardWidth,
        discardRect.height / myCardHeight
    );

    const flyingCard = document.createElement('div');
    flyingCard.className = 'flying-card discard';
    const cardInfo = CARD_INFO[card] || { name: `卡牌${card}`, description: '' };
    flyingCard.style.left = `${startX}px`;
    flyingCard.style.top = `${startY}px`;
    flyingCard.style.transformOrigin = 'center center';
    flyingCard.style.transform = `translate(-50%, -50%) scale(${initialScale}) rotate(0deg)`;
    flyingCard.style.setProperty('--target-x', `${deltaX}px`);
    flyingCard.style.setProperty('--target-y', `${deltaY}px`);
    flyingCard.style.setProperty('--initial-scale', initialScale.toString());
    flyingCard.style.setProperty('--target-scale', targetScale.toString());
    flyingCard.style.backgroundImage = `url('${getCardImageUrl(card)}')`;
    flyingCard.innerHTML = `
        <div class="card-overlay">
            <div class="card-name">${cardInfo.name}</div>
            <div class="card-description">${cardInfo.description}</div>
        </div>
    `;

    boardEl.appendChild(flyingCard);
    isCardDiscardAnimating = true;

    requestAnimationFrame(() => {
        flyingCard.classList.add('animate');
    });

    setTimeout(() => {
        if (flyingCard.parentNode) {
            flyingCard.parentNode.removeChild(flyingCard);
        }
        isCardDiscardAnimating = false;
        updateDiscardPileView();
        // 动画完成后，如果当前是我的回合，更新抽牌堆状态
        if (gameState && gameState.currentPlayerId === socket.id) {
            requestAnimationFrame(() => {
                updateDeckInteraction(canDrawFromDeckNow());
                updateDiscardInteraction(canPlayCardNow());
            });
        }
    }, CARD_DISCARD_ANIMATION_TOTAL_MS);
}

function registerImplicitDiscards(actionSequence) {
    if (!gameState || !playerInfo) return;

    playerInfo.forEach(player => {
        const status = gameState.playerStatus?.[player.id];
        if (!status) return;
        const lastCard = status.lastCardPlayed;
        if (typeof lastCard !== 'number') return;

        if (lastCard === 7) {
            const handled = lastHandledDiscards[player.id];
            if (handled && handled.card === 7) {
                return;
            }
            recordDiscardEvent(player.id, 7, actionSequence);
        }
    });
}

function renderGameBoard() {
    const boardEl = document.getElementById('players-board');
    if (!boardEl || !gameState || !playerInfo) return;

    // 如果动画正在进行，跳过渲染，避免中断动画
    if (isCardDrawAnimating) {
        updateDeckInteraction(false);
        updateDiscardInteraction(false);
        return;
    }

    // 找到自己的位置
    const myIndex = playerInfo.findIndex(p => p.id === socket.id);
    if (myIndex === -1) return;

    // 分离自己和对手
    const myPlayer = playerInfo[myIndex];
    // opponents 包含所有非自己的玩家（包括出局的），以保持布局不变
    const opponents = playerInfo.filter((p, i) => i !== myIndex);
    const activePlayers = playerInfo.filter(p => !gameState.playerStatus[p.id]?.isOut);
    const playerCount = activePlayers.length;

    // 清空棋盘（但保留动画卡牌）
    // 保存动画元素（如果存在）
    const flyingCards = Array.from(boardEl.querySelectorAll('.flying-card'));
    boardEl.innerHTML = '';
    // 重新添加动画元素（如果存在）
    flyingCards.forEach(card => {
        if (card && card.parentNode === null) {
            boardEl.appendChild(card);
        }
    });
    
    // 更新牌堆数量
    updateDeckCount();
    updateDeckInteraction(canDrawFromDeckNow());
    updateDiscardInteraction(canPlayCardNow());
    updateDiscardPileView();

    // 获取桌面尺寸
    const tableWidth = boardEl.offsetWidth || window.innerWidth;
    const tableHeight = boardEl.offsetHeight || window.innerHeight;
    
    // 桌面分区：上面2/3是其他玩家区域，下面1/3是自己的区域
    const opponentAreaHeight = tableHeight * (2 / 3);
    const myAreaHeight = tableHeight * (1 / 3);
    
    // 卡牌尺寸
    const opponentCardWidth = 100;
    const opponentCardHeight = 140;
    const myCardWidth = 140;
    const myCardHeight = 196;
    const myCardsGap = 12; // 两张卡牌之间的间距
    
    // 边距
    const margin = 60;
    
    // 根据对手数量计算固定位置
    const opponentPositions = getOpponentPositions(opponents.length, tableWidth, opponentAreaHeight, margin);
    
    // 先获取自己的回合状态（在渲染对手前需要知道）
    const myHand = playerState?.hand || [];
    const isMyTurn = playerState?.isMyTurn || false;
    const selectedCard = selectedCardIndex !== null ? myHand[selectedCardIndex] : null;
    const selectedCardRequiresTarget = selectedCard ? getCardRequiresTarget(selectedCard) : false;
    
    // 渲染对手卡牌
    opponents.forEach((opponent, index) => {
        const status = gameState.playerStatus[opponent.id] || {};
        const isOut = status.isOut || false;
        const isProtected = status.isProtected || false;
        const isCurrentPlayer = gameState.currentPlayerId === opponent.id;
        const opponentHand = gameState.playerHands[opponent.id] || [];
        // 如果该对手正在播放抽牌动画，使用旧的手牌数量（只有一张牌）
        let handCount = opponentHand.length;
        if (opponentCardDrawAnimating === opponent.id && previousOpponentHands[opponent.id] !== undefined) {
            handCount = previousOpponentHands[opponent.id]; // 使用旧的手牌数量
        }
        
        // 更新对手手牌记录（用于检测抽牌）
        if (!previousOpponentHands.hasOwnProperty(opponent.id)) {
            previousOpponentHands[opponent.id] = handCount;
        }
        
        const position = opponentPositions[index];
        
        const slotEl = document.createElement('div');
        // 判断是否可以选择这个对手作为目标
        // 两种情况：1. 正在等待选择目标（waitingForTarget）；2. 卡牌已选中但还没打出，且卡牌需要选择目标
        const selectedCard = selectedCardIndex !== null ? myHand[selectedCardIndex] : null;
        const selectedCardRequiresTarget = selectedCard ? getCardRequiresTarget(selectedCard) : false;
        const canSelect = (waitingForTarget && availableTargets.includes(opponent.id)) || 
                         (selectedCardIndex !== null && playedCardIndex === null && isMyTurn && !waitingForTarget && !waitingForGuess && selectedCardRequiresTarget);
        
        slotEl.className = `player-card-slot other ${isOut ? 'out' : ''} ${isProtected ? 'protected' : ''} ${isCurrentPlayer ? 'current' : ''} ${canSelect ? 'selectable' : ''}`;
        slotEl.style.left = `${position.x}px`;
        slotEl.style.top = `${position.y}px`;
        slotEl.style.transform = 'translate(-50%, -50%)';
        slotEl.dataset.playerId = opponent.id;
        
        // 如果对手出局，显示手牌内容（正面朝上）并黑白化，位置不变
        // 优先从 playerHands 获取，如果没有则从 playerStatus.eliminatedCard 获取
        if (isOut) {
            let eliminatedCard = null;
            if (handCount > 0) {
                eliminatedCard = opponentHand[0]; // 出局时通常只有一张手牌
            } else if (status.eliminatedCard) {
                eliminatedCard = status.eliminatedCard; // 从 playerStatus 中获取出局时的手牌
            }
            
            if (eliminatedCard) {
                const cardInfo = CARD_INFO[eliminatedCard] || { name: `卡牌${eliminatedCard}`, description: '' };
                slotEl.innerHTML = `
                    <div class="player-name">${opponent.name}</div>
                    <div class="opponent-card-wrapper">
                        <div class="opponent-card out eliminated" style="background-image: url('${getCardImageUrl(eliminatedCard)}')">
                            <div class="card-overlay">
                                <div class="card-name">${cardInfo.name}</div>
                                <div class="card-description">${cardInfo.description}</div>
                            </div>
                        </div>
                        <div class="out-overlay"></div>
                    </div>
                `;
            } else {
                // 如果没有手牌信息，显示背面（这种情况不应该发生，但作为后备）
                slotEl.innerHTML = `
                    <div class="player-name">${opponent.name}</div>
                    <div class="opponent-card out">
                    </div>
                `;
            }
        } else {
            // 显示重叠的卡牌图像（卡牌背面）
            let cardsHtml = '';
            if (handCount > 0) {
                // 根据手牌数量显示重叠的卡牌
                for (let i = 0; i < handCount; i++) {
                    const offsetX = i * 15; // 每张牌向右偏移15px，形成重叠效果
                    const zIndex = i + 1; // 后面的牌z-index更高，显示在上层（后发的牌在上面）
                    cardsHtml += `
                        <div class="opponent-card-stack" style="left: ${offsetX}px; z-index: ${zIndex};">
                            <div class="opponent-card"></div>
                        </div>
                    `;
                }
            }
            slotEl.innerHTML = `
                <div class="player-name">${opponent.name}</div>
                <div class="opponent-cards-container">
                    ${cardsHtml}
                </div>
            `;
        }
        
        // 添加点击事件
        if (canSelect) {
            slotEl.addEventListener('click', () => {
                selectTarget(opponent.id);
            }, { signal: controller.signal });
        }
        
        boardEl.appendChild(slotEl);
    });
    
    // 渲染自己的卡牌（在下方区域）
    // myHand 和 isMyTurn 已在上面定义
    
    // 计算自己的卡牌总宽度
    const myCardsTotalWidth = myHand.length === 2 ? myCardWidth * 2 + myCardsGap : myCardWidth;
    
    // 计算自己的卡牌位置（严格居中，确保完全在桌面内）
    const myCardsHalfWidth = myCardsTotalWidth / 2;
    let myX = tableWidth / 2; // 默认居中
    
    // 检查是否超出边界，如果超出则调整到可显示区域
    const minX = margin + myCardsHalfWidth;
    const maxX = tableWidth - margin - myCardsHalfWidth;
    if (myX < minX) {
        myX = minX;
    } else if (myX > maxX) {
        myX = maxX;
    }
    // 如果桌面太小，保持居中但确保不超出
    if (myCardsTotalWidth > tableWidth - margin * 2) {
        myX = tableWidth / 2; // 强制居中，即使稍微超出也要居中
    }
    
    // 计算自己的卡牌总高度（包括名字、卡牌）
    const myNameHeight = 35;
    let myTotalHeight = myNameHeight + myCardHeight;
    
    // 确保卡牌底部不超出桌面，顶部也不超出自己的区域
    const bottomMargin = 15; // 底部边距
    const topMargin = 15; // 顶部边距（相对于自己区域）
    const maxY = tableHeight - myTotalHeight / 2 - bottomMargin; // 底部不超出
    const minY = opponentAreaHeight + myTotalHeight / 2 + topMargin; // 顶部不超出自己的区域
    
    // 计算理想位置（在自己区域的中心偏下）
    const myAreaCenterY = opponentAreaHeight + myAreaHeight / 2;
    const preferredY = myAreaCenterY + myAreaHeight * 0.15; // 稍微偏下
    
    // 确保在安全范围内
    const myY = Math.min(maxY, Math.max(minY, preferredY));
    const myStatus = gameState.playerStatus[myPlayer.id] || {};
    const canSelectSelf = waitingForTarget && availableTargets.includes(myPlayer.id);
    
    const mySlotEl = document.createElement('div');
    mySlotEl.className = `player-card-slot self ${myStatus.isOut ? 'out' : ''} ${myStatus.isProtected ? 'protected' : ''} ${isMyTurn ? 'current' : ''} ${canSelectSelf ? 'selectable' : ''}`;
    // 使用绝对定位，确保居中
    mySlotEl.style.position = 'absolute';
    mySlotEl.style.left = `${myX}px`;
    mySlotEl.style.top = `${myY}px`;
    mySlotEl.style.transform = 'translate(-50%, -50%)';
    mySlotEl.style.textAlign = 'center';
    mySlotEl.dataset.playerId = myPlayer.id;
    
    if (myHand.length === 0 && !myStatus.isOut) {
        mySlotEl.innerHTML = `
            <div class="player-name">${myPlayer.name}</div>
            <div class="opponent-card out">出局</div>
        `;
    } else if (myHand.length === 1 || myStatus.isOut) {
        // 只有一张牌，或者出局时，直接显示手牌
        // 如果出局，只显示第一张牌并黑白化，位置和只有一张手牌时一样
        let card = null;
        if (myHand.length > 0) {
            card = myHand[0];
        } else if (myStatus.eliminatedCard) {
            card = myStatus.eliminatedCard; // 从 playerStatus 中获取出局时的手牌
        }
        
        if (card) {
            const cardInfo = CARD_INFO[card] || { name: `卡牌${card}`, description: '' };
            
            if (myStatus.isOut) {
                // 出局时，显示手牌并黑白化，位置和只有一张手牌时一样
                mySlotEl.innerHTML = `
                    <div class="player-name">${myPlayer.name}</div>
                    <div class="my-cards-container">
                        <div class="my-card-wrapper">
                            <div class="my-card eliminated" style="background-image: url('${getCardImageUrl(card)}')">
                                <div class="card-overlay">
                                    <div class="card-name">${cardInfo.name}</div>
                                    <div class="card-description">${cardInfo.description}</div>
                                </div>
                            </div>
                            <div class="out-overlay"></div>
                        </div>
                    </div>
                `;
            } else {
                mySlotEl.innerHTML = `
                    <div class="player-name">${myPlayer.name}</div>
                    <div class="my-cards-container">
                        ${createMyCardHtml(card, { index: 0 })}
                    </div>
                `;
            }
        } else {
            // 如果没有手牌信息，显示出局标记
            mySlotEl.innerHTML = `
                <div class="player-name">${myPlayer.name}</div>
                <div class="opponent-card out">出局</div>
            `;
        }
    } else {
        // 两张牌，横向并排显示
        mySlotEl.innerHTML = `
            <div class="player-name">${myPlayer.name}${canSelectSelf ? ' (可点击选择自己)' : ''}</div>
            <div class="my-cards-container">
                ${myHand.map((card, index) => {
                    const isSelected = selectedCardIndex === index;
                    const isPlayed = playedCardIndex === index;
                    const isHidden = hiddenCardIndex === index; // 新抓的牌需要隐藏
                    const isPlayable = isMyTurn && !waitingForTarget && !waitingForGuess && !isCardDrawAnimating && !isHidden;
                    return createMyCardHtml(card, {
                        index,
                        isPlayable,
                        isSelected,
                        isPlayed,
                        isHidden
                    });
                }).join('')}
            </div>
        `;
        
        // 添加点击事件（动画进行时不可点击）
        if (isMyTurn && !waitingForTarget && !waitingForGuess && !isCardDrawAnimating) {
            mySlotEl.querySelectorAll('.my-card.playable').forEach(cardEl => {
                cardEl.addEventListener('click', () => {
                    const cardIndex = parseInt(cardEl.dataset.cardIndex);
                    // 如果卡牌已打出（透明），不处理
                    if (playedCardIndex === cardIndex) {
                        return;
                    }
                    // 只选中卡牌，不直接打出
                    selectCard(cardIndex);
                }, { signal: controller.signal });
            });
        }
        
        // 如果可以选择自己作为目标，添加点击事件（点击名字区域）
        if (canSelectSelf && waitingForTarget) {
            const nameEl = mySlotEl.querySelector('.player-name');
            if (nameEl) {
                nameEl.style.cursor = 'pointer';
                nameEl.style.textDecoration = 'underline';
                nameEl.addEventListener('click', (e) => {
                    e.stopPropagation();
                    selectTarget(myPlayer.id);
                }, { signal: controller.signal });
            }
        }
    }
    
    boardEl.appendChild(mySlotEl);
}

// 根据对手数量计算固定位置
function getOpponentPositions(count, tableWidth, areaHeight, margin) {
    const positions = [];
    const cardWidth = 100;
    const cardHeight = 140;
    const nameHeight = 40; // 玩家名称高度
    const totalHeight = cardHeight + nameHeight;
    
    switch (count) {
        case 1:
            // 2人游戏：对手在正对面（上方居中）
            positions.push({
                x: tableWidth / 2,
                y: areaHeight / 2
            });
            break;
            
        case 2:
            // 3人游戏：对手1在左上角，对手2在右上角
            positions.push({
                x: margin + cardWidth / 2,
                y: margin + totalHeight / 2
            });
            positions.push({
                x: tableWidth - margin - cardWidth / 2,
                y: margin + totalHeight / 2
            });
            break;
            
        case 3:
            // 4人游戏：对手1在左侧，对手2在正对面（上方），对手3在右侧
            positions.push({
                x: margin + cardWidth / 2,
                y: areaHeight / 2
            });
            positions.push({
                x: tableWidth / 2,
                y: margin + totalHeight / 2
            });
            positions.push({
                x: tableWidth - margin - cardWidth / 2,
                y: areaHeight / 2
            });
            break;
            
        case 4:
            // 5人游戏：对手1在左侧，对手2在上偏左，对手3在上偏右，对手4在右侧
            const topY = margin + totalHeight / 2;
            const midY = areaHeight / 2;
            const leftX = margin + cardWidth / 2;
            const rightX = tableWidth - margin - cardWidth / 2;
            const topLeftX = tableWidth * 0.25;
            const topRightX = tableWidth * 0.75;
            
            positions.push({
                x: leftX,
                y: midY
            });
            positions.push({
                x: topLeftX,
                y: topY
            });
            positions.push({
                x: topRightX,
                y: topY
            });
            positions.push({
                x: rightX,
                y: midY
            });
            break;
            
        default:
            // 如果超过5人，使用圆形布局（但这种情况不应该发生）
            const radius = Math.min(tableWidth, areaHeight) * 0.3;
            const centerX = tableWidth / 2;
            const centerY = areaHeight / 2;
            for (let i = 0; i < count; i++) {
                const angle = (i * 2 * Math.PI) / count - Math.PI / 2;
                positions.push({
                    x: centerX + radius * Math.cos(angle),
                    y: centerY + radius * Math.sin(angle)
                });
            }
    }
    
    return positions;
}

function selectCard(cardIndex) {
    // 选中卡牌，准备出牌（但还没真正打出）
    // 如果点击的是已选中的卡牌，取消选择
    if (selectedCardIndex === cardIndex) {
        selectedCardIndex = null;
        renderGameBoard();
        return;
    }
    
    // 选中卡牌
    selectedCardIndex = cardIndex;
    renderGameBoard();
}

// 判断卡牌是否需要选择目标
function getCardRequiresTarget(card) {
    // 需要选择目标的卡牌：1(卫兵), 2(牧师), 3(男爵), 5(王子), 6(国王)
    return [1, 2, 3, 5, 6].includes(card);
}

function playCard(cardIndex) {
    // 记录已选中的卡牌（用于显示效果）
    // 注意：playedCardIndex 会在收到 action_required 后设置，表示卡牌已打出
    selectedCardIndex = cardIndex;
    
    socket.emit('game_action', {
        roomId,
        gameType: 'loveletter',
        action: 'play_card',
        actionData: { cardIndex }
    });
    
    // 发送请求后立即渲染，此时卡牌还是选中的，等待服务器响应
    renderGameBoard();
}

function handleYourTurn(data) {
    playerState = data.playerState;
    waitingForTarget = false;
    waitingForGuess = false;
    availableTargets = [];
    guessTargetPlayerId = null;
    currentAction = null;
    handleActionCompleted(); // 清除选中状态和已打出标记
    // 记录当前回合开始时间
    currentTurnStartTime = Date.now();
    updateMessage('轮到你的回合！');
    addLogEntry('⏰ 轮到你的回合！', 'turn');
    renderGameBoard();
    renderGameLog();
    // renderGameBoard 中已经调用了更新函数
}

// 标记动画是否正在进行
let isCardDrawAnimating = false;
// 标记需要隐藏的卡牌索引（新抓的牌在动画完成前隐藏）
let hiddenCardIndex = null;

function handleCardDrawn(data) {
    playerState = data.playerState;
    const cardName = CARD_INFO[data.drawnCard]?.name || data.drawnCard;
    updateMessage(`你抽到了一张牌: ${cardName}`);
    addLogEntry(`🃏 你抽到了 ${cardName} (${data.drawnCard})`, 'action');
    
    // 找到新抓的牌在手牌中的索引（应该是最后一张）
    const myHand = playerState?.hand || [];
    hiddenCardIndex = myHand.length - 1; // 新抓的牌是最后一张
    
    // 清除选中状态，避免动画时显示"出牌"按钮
    selectedCardIndex = null;
    
    // 先渲染游戏板，隐藏新抓的牌，确保抓牌按钮隐藏，两张牌放到指定位置
    isCardDrawAnimating = false; // 临时设为false，允许渲染
    renderGameBoard();
    
    // 标记动画开始
    isCardDrawAnimating = true;
    
    // 创建动画卡牌，从牌堆飞到玩家手牌位置
    animateCardDraw(data.drawnCard);
    
    // 延迟更新游戏板，等待动画完成
    setTimeout(() => {
        isCardDrawAnimating = false;
        hiddenCardIndex = null; // 清除隐藏标记
        renderGameBoard(); // 显示新抓的牌，renderGameBoard 中已经调用了更新函数
    }, CARD_DRAW_ANIMATION_TOTAL_MS);
    
    renderGameLog();
}

function animateCardDraw(card) {
    const boardEl = document.getElementById('players-board');
    const deckEl = document.getElementById('deck');
    if (!boardEl || !deckEl) return;
    
    // 获取牌堆位置
    const deckRect = deckEl.getBoundingClientRect();
    const boardRect = boardEl.getBoundingClientRect();
    // 牌堆的中心位置（相对于 players-board）
    const deckX = deckRect.left - boardRect.left + deckRect.width / 2;
    const deckY = deckRect.top - boardRect.top + deckRect.height / 2;
    
    // 牌堆的实际大小（用于起始缩放）
    const deckWidth = deckRect.width;  // 100px
    const deckHeight = deckRect.height; // 140px
    
    // 获取玩家手牌位置（计算最终位置）
    const myHand = playerState?.hand || [];
    const myCardWidth = 140;
    const myCardHeight = 196;
    const myCardsGap = 12;
    const tableWidth = boardEl.offsetWidth || window.innerWidth;
    const tableHeight = boardEl.offsetHeight || window.innerHeight;
    const opponentAreaHeight = tableHeight * (2 / 3);
    const myAreaHeight = tableHeight * (1 / 3);
    const margin = 60;
    
    // 计算自己的卡牌总宽度
    const myCardsTotalWidth = myHand.length === 2 ? myCardWidth * 2 + myCardsGap : myCardWidth;
    const myCardsHalfWidth = myCardsTotalWidth / 2;
    let myX = tableWidth / 2;
    
    // 确保不超出边界
    const minX = margin + myCardsHalfWidth;
    const maxX = tableWidth - margin - myCardsHalfWidth;
    if (myX < minX) {
        myX = minX;
    } else if (myX > maxX) {
        myX = maxX;
    }
    if (myCardsTotalWidth > tableWidth - margin * 2) {
        myX = tableWidth / 2;
    }
    
    // 计算自己的卡牌位置（Y坐标）
    const myNameHeight = 35;
    const myTotalHeight = myNameHeight + myCardHeight;
    const bottomMargin = 15;
    const topMargin = 15;
    const maxY = tableHeight - myTotalHeight / 2 - bottomMargin;
    const minY = opponentAreaHeight + myTotalHeight / 2 + topMargin;
    const myAreaCenterY = opponentAreaHeight + myAreaHeight / 2;
    const preferredY = myAreaCenterY + myAreaHeight * 0.15;
    const myY = Math.min(maxY, Math.max(minY, preferredY));
    
    // 计算目标位置（新卡牌的位置）
    // 注意：此时 myHand 已经包含了新抽到的卡牌
    // slot 的中心在 (myX, myY)，使用 translate(-50%, -50%) 居中对齐
    // slot 内容从上到下：名字(myNameHeight) -> 卡牌容器 -> 按钮
    // 卡牌在卡牌容器中，需要计算卡牌中心相对于 players-board 的绝对位置
    
    // 计算卡牌中心位置
    // slot 使用 translate(-50%, -50%)，所以 slot 的中心在 (myX, myY)
    // slot 内容从上到下：名字(myNameHeight) -> 卡牌(myCardHeight)
    // slot 内容总高度 = myNameHeight + myCardHeight
    // slot 内容顶部 = myY - (myNameHeight + myCardHeight) / 2
    // 卡牌顶部 = slot 内容顶部 + myNameHeight = myY - (myNameHeight + myCardHeight) / 2 + myNameHeight
    // 卡牌中心 = 卡牌顶部 + myCardHeight / 2 = myY - (myNameHeight + myCardHeight) / 2 + myNameHeight + myCardHeight / 2
    // 简化：cardCenterY = myY + myNameHeight / 2
    const cardCenterY = myY + myNameHeight / 2;
    
    // 计算卡牌在 slot 中的 X 位置
    let cardCenterX = myX;
    if (myHand.length === 2) {
        // 两张牌时，新卡牌在右侧（第二张牌）
        // 第一张牌中心在 myX - myCardsGap/2 - myCardWidth/2
        // 第二张牌中心在 myX + myCardsGap/2 + myCardWidth/2
        // 或者更简单：第一张牌中心在 myX - (myCardWidth + myCardsGap) / 2
        //            第二张牌中心在 myX + (myCardWidth + myCardsGap) / 2
        cardCenterX = myX + (myCardWidth + myCardsGap) / 2;
    } else if (myHand.length === 1) {
        // 只有一张牌时，居中
        cardCenterX = myX;
    }
    
    // 计算相对移动距离（从牌堆中心到卡牌中心）
    const targetRelativeX = cardCenterX - deckX;
    const targetRelativeY = cardCenterY - deckY;
    
    // 创建动画卡牌
    const flyingCard = document.createElement('div');
    flyingCard.className = 'flying-card';
    const cardInfo = CARD_INFO[card] || { name: `卡牌${card}`, description: '' };
    flyingCard.style.backgroundImage = `url('${getCardImageUrl(card)}')`;
    flyingCard.innerHTML = `
        <div class="card-overlay">
            <div class="card-name">${cardInfo.name}</div>
            <div class="card-description">${cardInfo.description}</div>
        </div>
    `;
    
    // 设置起始位置（完全覆盖牌堆）
    // 动画卡牌大小是 140px x 196px，牌堆大小是 100px x 140px
    // 需要计算起始缩放比例，使动画卡牌完全覆盖牌堆
    const scaleX = deckWidth / myCardWidth;   // 100/140 ≈ 0.714
    const scaleY = deckHeight / myCardHeight; // 140/196 ≈ 0.714
    const initialScale = Math.min(scaleX, scaleY); // 使用较小的缩放比例以确保完全覆盖
    
    // 设置卡牌中心在牌堆中心
    flyingCard.style.left = `${deckX}px`;
    flyingCard.style.top = `${deckY}px`;
    flyingCard.style.transformOrigin = 'center center';
    // 初始状态必须和 keyframes 0% 完全一致，避免动画开始时的跳变
    flyingCard.style.transform = `translate(-50%, -50%) scale(${initialScale}) rotate(0deg)`;
    
    // 设置动画目标位置（相对于初始位置的距离）
    flyingCard.style.setProperty('--target-x', `${targetRelativeX}px`);
    flyingCard.style.setProperty('--target-y', `${targetRelativeY}px`);
    flyingCard.style.setProperty('--initial-scale', initialScale.toString());
    
    boardEl.appendChild(flyingCard);
    
    // 触发动画
    setTimeout(() => {
        flyingCard.classList.add('animate');
    }, 10);
    
    // 动画完成后移除元素
    setTimeout(() => {
        if (flyingCard.parentNode) {
            flyingCard.parentNode.removeChild(flyingCard);
        }
    }, CARD_DRAW_ANIMATION_TOTAL_MS);
}

function animateOpponentCardDraw(opponentId, onComplete) {
    const boardEl = document.getElementById('players-board');
    const deckEl = document.getElementById('deck');
    if (!boardEl || !deckEl) {
        if (onComplete) onComplete();
        return;
    }
    
    // 等待DOM更新
    requestAnimationFrame(() => {
        // 获取对手的slot元素（此时应该只有一张牌）
        const opponentSlotEl = getPlayerSlotElement(opponentId);
        if (!opponentSlotEl) {
            // 如果slot还不存在，延迟重试
            setTimeout(() => animateOpponentCardDraw(opponentId, onComplete), 100);
            return;
        }
        
        // 获取对手卡牌容器
        const opponentCardsContainer = opponentSlotEl.querySelector('.opponent-cards-container');
        if (!opponentCardsContainer) {
            // 如果容器还不存在，延迟重试
            setTimeout(() => animateOpponentCardDraw(opponentId, onComplete), 100);
            return;
        }
        
        // 获取牌堆位置
        const deckRect = deckEl.getBoundingClientRect();
        const boardRect = boardEl.getBoundingClientRect();
        const deckX = deckRect.left - boardRect.left + deckRect.width / 2;
        const deckY = deckRect.top - boardRect.top + deckRect.height / 2;
        
        // 牌堆的实际大小（用于起始缩放）
        const deckWidth = deckRect.width;  // 100px
        const deckHeight = deckRect.height; // 140px
        
        const opponentCardWidth = 100;
        const opponentCardHeight = 140;
        
        // 计算目标位置（新卡牌的位置，应该是最右侧的卡牌）
        // 对手卡牌容器相对于board的位置
        const containerRect = opponentCardsContainer.getBoundingClientRect();
        const containerX = containerRect.left - boardRect.left + containerRect.width / 2;
        const containerY = containerRect.top - boardRect.top + containerRect.height / 2;
        
        // 当前只有一张牌，新卡牌应该在第二张的位置（偏移15px）
        const cardOffsetX = 15; // 第二张牌向右偏移15px
        const targetX = containerX - (containerRect.width / 2) + (opponentCardWidth / 2) + cardOffsetX;
        const targetY = containerY;
        
        // 计算相对移动距离
        const targetRelativeX = targetX - deckX;
        const targetRelativeY = targetY - deckY;
        
        // 创建动画卡牌（使用卡牌背面）
        const flyingCard = document.createElement('div');
        flyingCard.className = 'flying-card opponent-draw';
        flyingCard.style.backgroundImage = `url('${CARD_BACK_IMAGE}')`;
        
        // 设置起始位置和缩放
        const scaleX = deckWidth / opponentCardWidth;   // 100/100 = 1.0
        const scaleY = deckHeight / opponentCardHeight; // 140/140 = 1.0
        const initialScale = Math.min(scaleX, scaleY);
        
        // 目标缩放（对手卡牌大小）
        const targetScale = 1.0;
        
        flyingCard.style.left = `${deckX}px`;
        flyingCard.style.top = `${deckY}px`;
        flyingCard.style.width = `${opponentCardWidth}px`;
        flyingCard.style.height = `${opponentCardHeight}px`;
        flyingCard.style.transformOrigin = 'center center';
        flyingCard.style.transform = `translate(-50%, -50%) scale(${initialScale}) rotate(0deg)`;
        
        // 设置动画目标位置
        flyingCard.style.setProperty('--target-x', `${targetRelativeX}px`);
        flyingCard.style.setProperty('--target-y', `${targetRelativeY}px`);
        flyingCard.style.setProperty('--initial-scale', initialScale.toString());
        flyingCard.style.setProperty('--target-scale', targetScale.toString());
        
        boardEl.appendChild(flyingCard);
        
        // 触发动画
        requestAnimationFrame(() => {
            flyingCard.classList.add('animate');
        });
        
        // 动画完成后移除元素并执行回调（刷新卡牌状态）
        setTimeout(() => {
            if (flyingCard.parentNode) {
                flyingCard.parentNode.removeChild(flyingCard);
            }
            // 执行回调，更新记录并刷新成两张牌
            if (onComplete) {
                onComplete();
            }
        }, CARD_DRAW_ANIMATION_TOTAL_MS);
    });
}

function updateDeckCount() {
    const deckCountEl = document.getElementById('deck-count');
    if (!deckCountEl || !gameState) return;
    
    // 计算剩余牌数（牌堆中的牌数）
    const deckLength = gameState.deck ? gameState.deck.length : 0;
    deckCountEl.textContent = `剩余${deckLength}张牌`;
    
    // 如果牌堆为空，降低透明度
    const deckContainerEl = document.getElementById('deck-container');
    if (deckContainerEl) {
        if (deckLength === 0) {
            deckContainerEl.style.opacity = '0.3';
        } else {
            deckContainerEl.style.opacity = '1';
        }
    }
}

function handleActionRequired(data) {
    const { action, playedCard, cardName, description, availableTargets: targets } = data;
    
    currentAction = action;
    let guardAutoSubmitted = false;
    
    // 卡牌已打出，设置已打出标记（使卡牌变透明）
    if (selectedCardIndex !== null) {
        if (!(playedCard === 1 && action === 'guess_card')) {
            playedCardIndex = selectedCardIndex;
        }
    }
    
    // 如果是卫兵猜牌，先选择目标玩家
    if (action === 'guess_card') {
        availableTargets = targets.map(t => t.id);
        
        if (guardAutoSubmitPending && stagedGuardTargetId && stagedGuardGuessCard !== null) {
            const targetId = stagedGuardTargetId;
            const guessedCard = stagedGuardGuessCard;
            guardAutoSubmitPending = false;
            stagedGuardTargetId = null;
            stagedGuardGuessCard = null;
            pendingTargetSelection = null;
            
            waitingForTarget = false;
            waitingForGuess = false;
            availableTargets = [];
            guessTargetPlayerId = null;
            currentAction = null;
            
            if (selectedCardIndex !== null) {
                playedCardIndex = selectedCardIndex;
            }
            
            const targetPlayer = playerInfo.find(p => p.id === targetId);
            const guessedCardName = CARD_INFO[guessedCard]?.name || `卡牌${guessedCard}`;
            updateMessage(`你打出了${cardName} (${playedCard})，猜测 ${targetPlayer?.name || '该玩家'} 的手牌为 ${guessedCardName}`);
            addLogEntry(`你打出了 ${cardName} (${playedCard})，猜测 ${targetPlayer?.name || '该玩家'} 的手牌为 ${guessedCardName}`, 'action');
            
            socket.emit('game_action', {
                roomId,
                gameType: 'loveletter',
                action: 'guess_card',
                actionData: { targetPlayerId: targetId, guessedCard }
            });
            
            renderGameBoard();
            guardAutoSubmitted = true;
        } else {
            waitingForTarget = true;
            waitingForGuess = false;
            guessTargetPlayerId = null;
            
            updateMessage(`你打出了${cardName} (${playedCard})。请先点击一个玩家作为目标`);
            addLogEntry(`你打出了 ${cardName} (${playedCard})`, 'action');
            renderGameBoard(); // 重新渲染，使目标可点击
            
            // 如果之前有延迟的目标选择，现在处理
            if (pendingTargetSelection) {
                const targetId = pendingTargetSelection;
                pendingTargetSelection = null;
                // 延迟处理，确保状态已更新
                setTimeout(() => {
                    selectTarget(targetId);
                }, 100);
            }
        }
    } else {
        // 其他需要选择玩家的卡牌
        waitingForTarget = true;
        waitingForGuess = false;
        guessTargetPlayerId = null;
        availableTargets = targets.map(t => t.id);
        
        // 对于王子(5)，如果可以选择自己，也添加到可选目标中
        if (playedCard === 5 && !availableTargets.includes(socket.id)) {
            availableTargets.push(socket.id);
        }
        
        updateMessage(`你打出了${cardName} (${playedCard})。${description}`);
        addLogEntry(`你打出了 ${cardName} (${playedCard})`, 'action');
        
        if (action === 'choose_player') {
            updateMessage(`请点击一个玩家作为目标${playedCard === 5 ? '（包括自己）' : ''}`);
            renderGameBoard(); // 重新渲染，使目标可点击
            
            // 如果之前有延迟的目标选择，现在处理
            if (pendingTargetSelection) {
                const targetId = pendingTargetSelection;
                pendingTargetSelection = null;
                // 延迟处理，确保状态已更新
                setTimeout(() => {
                    selectTarget(targetId);
                }, 100);
            }
        }
    }
    
    renderGameLog();
    
    if (guardAutoSubmitted) {
        return;
    }
}

function handleActionCompleted() {
    // 动作完成后，清除已打出的卡牌标记和选中状态
    playedCardIndex = null;
    selectedCardIndex = null;
    stagedGuardTargetId = null;
    stagedGuardGuessCard = null;
    guardAutoSubmitPending = false;
    // 更新交互状态
    requestAnimationFrame(() => {
        updateDeckInteraction(canDrawFromDeckNow());
        updateDiscardInteraction(canPlayCardNow());
    });
}

function selectTarget(targetPlayerId) {
    const myHand = playerState?.hand || [];
    const selectedCardValue = selectedCardIndex !== null ? myHand[selectedCardIndex] : null;
    
    // 如果卡牌还没打出，先根据卡牌类型处理
    if (selectedCardIndex !== null && playedCardIndex === null && selectedCardValue !== null) {
        // 卫兵牌在确认猜测前不立即打出
        if (selectedCardValue === 1 && !waitingForTarget && !currentAction) {
            stagedGuardTargetId = targetPlayerId;
            showCardGuessForTarget(targetPlayerId, { allowBack: true, stage: 'preplay' });
            return;
        }
        
        pendingTargetSelection = targetPlayerId;
        playCard(selectedCardIndex);
        // playCard 会发送请求，等待服务器响应 action_required
        // 等收到 action_required 后再处理目标选择
        return;
    }
    
    if (!waitingForTarget || !availableTargets.includes(targetPlayerId)) {
        return;
    }
    
    // 如果是卫兵猜牌，先记录目标玩家，然后显示猜测列表
    if (currentAction === 'guess_card') {
        waitingForTarget = false;
        waitingForGuess = true;
        guessTargetPlayerId = targetPlayerId;
        
        // 显示猜测卡牌列表
        showCardGuessForTarget(targetPlayerId, { allowBack: true, stage: 'action_required' });
    } else {
        // 其他卡牌，直接发送选择
        waitingForTarget = false;
        waitingForGuess = false;
        availableTargets = [];
        guessTargetPlayerId = null;
        currentAction = null;
        
        // 动作完成，清除已打出的卡牌标记
        handleActionCompleted();
        
        socket.emit('game_action', {
            roomId,
            gameType: 'loveletter',
            action: 'choose_player',
            actionData: { targetPlayerId }
        });
        
        renderGameBoard();
    }
}

function showCardGuessForTarget(targetPlayerId, options = {}) {
    const targetPlayer = playerInfo.find(p => p.id === targetPlayerId);
    if (!targetPlayer) return;
    
    const { allowBack = false, stage = 'action_required' } = options;
    const modal = document.createElement('div');
    modal.className = 'card-guess-modal';
    modal.id = 'card-guess-modal';
    const cardOptions = [2, 3, 4, 5, 6, 7, 8]; // 不能猜测卫兵（1）
    
    modal.innerHTML = `
        <div class="modal-content">
            <div class="modal-header">
                <h3>猜测 ${targetPlayer.name} 的手牌</h3>
                ${allowBack ? `<button class="modal-back-button" type="button">返回</button>` : ''}
            </div>
            <div class="card-guess-grid">
                ${cardOptions.map(card => {
                    const cardInfo = CARD_INFO[card] || { name: `卡牌${card}` };
                    return `
                        <button class="guess-card-button" data-card="${card}">
                            <div class="card-preview" style="background-image: url('${getCardImageUrl(card)}')">
                                <div class="card-overlay">
                                    <div class="card-name">${cardInfo.name}</div>
                                </div>
                            </div>
                        </button>
                    `;
                }).join('')}
            </div>
        </div>
    `;
    
    const existingModal = document.getElementById('card-guess-modal');
    if (existingModal) {
        existingModal.remove();
    }
    
    document.body.appendChild(modal);
    
    const closeModal = () => {
        const modalEl = document.getElementById('card-guess-modal');
        if (modalEl) {
            document.body.removeChild(modalEl);
        }
    };
    
    if (allowBack) {
        const backBtn = modal.querySelector('.modal-back-button');
        if (backBtn) {
            backBtn.addEventListener('click', () => {
                closeModal();
                if (stage === 'preplay') {
                    stagedGuardTargetId = null;
                    stagedGuardGuessCard = null;
                    guardAutoSubmitPending = false;
                    waitingForTarget = false;
                    waitingForGuess = false;
                    guessTargetPlayerId = null;
                    updateMessage('请选择要打出的卡牌或目标');
                    renderGameBoard();
                } else {
                    waitingForTarget = true;
                    waitingForGuess = false;
                    guessTargetPlayerId = null;
                    renderGameBoard();
                }
            }, { signal: controller.signal });
        }
    }
    
    modal.querySelectorAll('.guess-card-button').forEach(btn => {
        btn.addEventListener('click', () => {
            const guessedCard = parseInt(btn.dataset.card, 10);
            closeModal();
            
            if (stage === 'preplay') {
                stagedGuardGuessCard = guessedCard;
                guardAutoSubmitPending = true;
                waitingForTarget = true;
                waitingForGuess = false;
                guessTargetPlayerId = null;
                updateMessage(`你准备对 ${targetPlayer.name} 使用卫兵，请稍候...`);
                // 开始真正打出卫兵
                playCard(selectedCardIndex);
            } else {
                waitingForTarget = false;
                waitingForGuess = false;
                availableTargets = [];
                guessTargetPlayerId = null;
                currentAction = null;
                
                if (selectedCardIndex !== null) {
                    playedCardIndex = selectedCardIndex;
                }
                
                socket.emit('game_action', {
                    roomId,
                    gameType: 'loveletter',
                    action: 'guess_card',
                    actionData: { targetPlayerId, guessedCard }
                });
                
                renderGameBoard();
            }
        }, { signal: controller.signal });
    });
}

function handleRevealHand(data) {
    const { playerId, hand } = data;
    const player = playerInfo.find(p => p.id === playerId);
    const cardName = CARD_INFO[hand[0]]?.name || hand[0];
    updateMessage(`你看到了 ${player?.name} 的手牌: ${cardName} (${hand[0]})`);
    addLogEntry(`👁️ 你使用牧师看到了 ${player?.name} 的手牌: ${cardName}`, 'important');
    renderGameLog();
}

function handleGameStateUpdated(data) {
    const previousCurrentPlayerId = gameState?.currentPlayerId ?? null;
    
    // 如果游戏已结束，不处理状态更新（除非是新的游戏开始）
    if (isGameEnded && data.state?.isGameEnded) {
        return;
    }
    
    // 在更新gameState之前，更新对手手牌记录（用于检测抽牌）
    if (gameState && data.state) {
        playerInfo.forEach(player => {
            if (player.id !== socket.id) {
                // 如果该对手正在播放抽牌动画，不更新 previousOpponentHands（保持旧值）
                if (opponentCardDrawAnimating === player.id) {
                    return;
                }
                const oldHandCount = (gameState.playerHands[player.id] || []).length;
                const newHandCount = (data.state.playerHands?.[player.id] || []).length;
                // 更新记录（无论增加还是减少）
                if (oldHandCount !== newHandCount) {
                    // 只有在手牌数量增加时才记录旧值（用于检测抽牌）
                    // 如果减少，直接更新为新值
                    if (newHandCount > oldHandCount) {
                        previousOpponentHands[player.id] = oldHandCount;
                    } else {
                        previousOpponentHands[player.id] = newHandCount;
                    }
                }
            }
        });
    }
    
    gameState = data.state;
    if (data.playerState) {
        playerState = data.playerState;
    }
    
    // 检测当前玩家是否改变
    const currentPlayerIdChanged = previousCurrentPlayerId !== gameState?.currentPlayerId;
    
    // 如果接收到新游戏的状态（游戏未结束），重置游戏结束标志
    if (gameState && !gameState.isGameEnded) {
        isGameEnded = false;
    }
    
    // 如果状态更新后不再等待目标，清除等待状态
    if (!gameState.waitingForAction) {
        waitingForTarget = false;
        waitingForGuess = false;
        availableTargets = [];
        guessTargetPlayerId = null;
        currentAction = null;
        handleActionCompleted(); // 清除选中状态和已打出标记
        
        // 清理可能存在的猜测模态框
        const modalEl = document.getElementById('card-guess-modal');
        if (modalEl) {
            document.body.removeChild(modalEl);
        }
    }
    
    const actionResult = data.actionResult;
    let currentActionSequence = actionSequenceCounter;
    if (actionResult) {
        currentActionSequence = ++actionSequenceCounter;
        handleActionResult(actionResult, { previousCurrentPlayerId }, currentActionSequence);
    }
    
    registerImplicitDiscards(currentActionSequence);
    
    // 如果当前玩家改变，立即更新抽牌堆状态
    if (currentPlayerIdChanged) {
        // 直接更新，因为现在使用 gameState.currentPlayerId 判断，不需要等待 playerState 更新
        updateDeckInteraction(canDrawFromDeckNow());
        updateDiscardInteraction(canPlayCardNow());
        // 也使用 requestAnimationFrame 确保 DOM 更新
        requestAnimationFrame(() => {
            updateDeckInteraction(canDrawFromDeckNow());
            updateDiscardInteraction(canPlayCardNow());
        });
    }
    
    // 如果动画正在进行，延迟渲染，避免中断动画
    if (isCardDrawAnimating) {
        // 延迟到动画完成后渲染
        setTimeout(() => {
            if (!isCardDrawAnimating) {
                renderGameBoard();
            }
        }, CARD_DRAW_ANIMATION_TOTAL_MS);
    } else {
        renderGameBoard();
    }
    updateGameLog(actionResult);
}

function handleActionResult(actionResult, context = {}, actionSequence = actionSequenceCounter) {
    const actingPlayerId = actionResult.playerId ?? context.previousCurrentPlayerId ?? null;
    
    // 检测对手抽牌并触发动画
    if (actionResult.type === 'card_drawn' && actionResult.playerId && actionResult.playerId !== socket.id) {
        const opponentId = actionResult.playerId;
        const previousHandCount = previousOpponentHands[opponentId] || 0;
        const currentHandCount = (gameState.playerHands[opponentId] || []).length;
        
        // 如果手牌数量增加，且是当前玩家的回合，触发动画
        if (currentHandCount > previousHandCount && gameState.currentPlayerId === opponentId) {
            // 标记该对手正在播放抽牌动画
            opponentCardDrawAnimating = opponentId;
            // 先不更新 previousOpponentHands，保持只有一张牌的状态
            // 延迟一点以确保DOM已更新
            setTimeout(() => {
                animateOpponentCardDraw(opponentId, () => {
                    // 动画完成后的回调：更新记录、清除动画标记并刷新
                    previousOpponentHands[opponentId] = currentHandCount;
                    opponentCardDrawAnimating = null;
                    renderGameBoard();
                });
            }, 50);
        } else {
            // 如果不是抽牌动画的情况，正常更新记录
            previousOpponentHands[opponentId] = currentHandCount;
        }
    }
    
    switch (actionResult.type) {
        case 'card_played':
            const player = playerInfo.find(p => p.id === actionResult.playerId);
            if (player && player.id !== socket.id) {
                updateMessage(`${player.name} 打出了一张牌`);
            }
            break;
            
        case 'player_out':
            const outPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (outPlayer) {
                updateMessage(`❌ ${outPlayer.name} 出局了！原因: ${actionResult.reason}`);
            }
            break;
            
        case 'guard_success':
            const guardPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const targetPlayer = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            const guessedCardName = CARD_INFO[actionResult.guessedCard]?.name;
            if (guardPlayer && targetPlayer) {
                updateMessage(`✅ ${guardPlayer.name} 猜对了！${targetPlayer.name} 的手牌是 ${guessedCardName}，出局！`);
            }
            break;
            
        case 'guard_fail':
            const failGuardPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (failGuardPlayer) {
                updateMessage(`❌ ${failGuardPlayer.name} 猜错了！`);
            }
            break;
            
        case 'baron_compare':
            if (actionResult.loserId) {
                const loser = playerInfo.find(p => p.id === actionResult.loserId);
                if (loser) {
                    updateMessage(`❌ ${loser.name} 的手牌较小 (${actionResult.myCard} vs ${actionResult.opponentCard})，出局！`);
                }
            } else {
                updateMessage(`平局！没有人出局`);
            }
            break;
            
        case 'handmaid':
            const protectedPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (protectedPlayer) {
                updateMessage(`🛡️ ${protectedPlayer.name} 使用了侍女，下一回合前受保护！`);
            }
            break;
            
        case 'prince_discard_princess':
            const princePlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const princessPlayer = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            if (princePlayer && princessPlayer) {
                updateMessage(`❌ ${princePlayer.name} 让 ${princessPlayer.name} 弃掉了公主，${princessPlayer.name} 出局！`);
            }
            break;
            
        case 'prince_discard':
            const princePlayer2 = playerInfo.find(p => p.id === actionResult.playerId);
            const targetPlayer2 = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            const discardedCardName = CARD_INFO[actionResult.discardedCard]?.name;
            if (princePlayer2 && targetPlayer2) {
                updateMessage(`${princePlayer2.name} 让 ${targetPlayer2.name} 弃掉了 ${discardedCardName}，并抽取新牌`);
            }
            break;
            
        case 'king_swap':
            const kingPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const swapTarget = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            if (kingPlayer && swapTarget) {
                updateMessage(`${kingPlayer.name} 与 ${swapTarget.name} 交换了手牌`);
            }
            break;
            
        case 'turn_start':
            const currentPlayer = playerInfo.find(p => p.id === actionResult.currentPlayerId);
            if (currentPlayer) {
                // 记录当前回合开始时间
                currentTurnStartTime = Date.now();
                if (currentPlayer.id !== socket.id) {
                    updateMessage(`轮到 ${currentPlayer.name} 的回合`);
                }

                // 如果弃牌动画正在进行，不立即更新（动画完成回调会处理）
                // 否则立即更新抽牌堆状态
                if (!isCardDiscardAnimating) {
                    updateDeckInteraction(canDrawFromDeckNow());
                    updateDiscardInteraction(canPlayCardNow());
                    // 也使用 requestAnimationFrame 确保 DOM 更新
                    requestAnimationFrame(() => {
                        updateDeckInteraction(canDrawFromDeckNow());
                        updateDiscardInteraction(canPlayCardNow());
                    });
                }
                // 如果动画正在进行，animateCardDiscard 的完成回调会在动画结束后更新
            }
            break;
    }

    switch (actionResult.type) {
        case 'card_played': {
            const playerId = actionResult.playerId;
            const status = gameState.playerStatus?.[playerId];
            const lastCard = status?.lastCardPlayed;
            if (playerId && typeof lastCard === 'number') {
                recordDiscardEvent(playerId, lastCard, actionSequence, { sourceType: 'card_played' });
            }
            break;
        }
        case 'handmaid':
            if (actingPlayerId) {
                recordDiscardEvent(actingPlayerId, 4, actionSequence);
            }
            break;
        case 'card_discarded':
            recordDiscardEvent(actionResult.playerId, actionResult.card, actionSequence);
            break;
        case 'prince_discard':
        case 'prince_discard_princess':
            if (actingPlayerId) {
                const handled = lastHandledDiscards[actingPlayerId];
                if (handled && handled.card === 5) {
                    handled.actionSequence = actionSequence;
                } else {
                    recordDiscardEvent(actingPlayerId, 5, actionSequence);
                }
            }
            break;
        case 'player_out':
            if (actionResult.reason === '打出公主') {
                recordDiscardEvent(actionResult.playerId, 8, actionSequence);
            }
            break;
        default:
            break;
    }
}

function updateGameLog(actionResult) {
    if (!actionResult) return;
    
    // 根据动作类型添加日志
    switch (actionResult.type) {
        case 'card_played':
            const player = playerInfo.find(p => p.id === actionResult.playerId);
            if (player) {
                addLogEntry(`${player.name} 打出了一张牌`, 'action');
            }
            break;
            
        case 'player_out':
            const outPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (outPlayer) {
                addLogEntry(`❌ ${outPlayer.name} 出局 (${actionResult.reason})`, 'important');
            }
            break;
            
        case 'guard_success':
            const guardPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const targetPlayer = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            const guessedCardName = CARD_INFO[actionResult.guessedCard]?.name;
            if (guardPlayer && targetPlayer) {
                addLogEntry(`✅ ${guardPlayer.name} 使用卫兵猜对了！${targetPlayer.name} 的手牌是 ${guessedCardName}`, 'success');
            }
            break;
            
        case 'guard_fail':
            const failGuardPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (failGuardPlayer) {
                addLogEntry(`❌ ${failGuardPlayer.name} 使用卫兵猜错了`, 'info');
            }
            break;
            
        case 'baron_compare':
            if (actionResult.loserId) {
                const loser = playerInfo.find(p => p.id === actionResult.loserId);
                if (loser) {
                    addLogEntry(`⚔️ ${loser.name} 在男爵对决中失败 (${actionResult.myCard} vs ${actionResult.opponentCard})`, 'important');
                }
            } else {
                addLogEntry(`🤝 男爵对决平局！没有人出局`, 'info');
            }
            break;
            
        case 'handmaid':
            const protectedPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (protectedPlayer) {
                addLogEntry(`🛡️ ${protectedPlayer.name} 使用侍女，下一回合前受保护`, 'info');
            }
            break;
            
        case 'prince_discard_princess':
            const princePlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const princessPlayer = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            if (princePlayer && princessPlayer) {
                addLogEntry(`👑 ${princePlayer.name} 让 ${princessPlayer.name} 弃掉了公主！`, 'important');
            }
            break;
            
        case 'prince_discard':
            const princePlayer2 = playerInfo.find(p => p.id === actionResult.playerId);
            const targetPlayer2 = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            const discardedCardName = CARD_INFO[actionResult.discardedCard]?.name;
            if (princePlayer2 && targetPlayer2) {
                addLogEntry(`👑 ${princePlayer2.name} 使用王子，${targetPlayer2.name} 弃掉了 ${discardedCardName}`, 'action');
            }
            break;
            
        case 'king_swap':
            const kingPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const swapTarget = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            if (kingPlayer && swapTarget) {
                addLogEntry(`👑 ${kingPlayer.name} 使用国王与 ${swapTarget.name} 交换了手牌`, 'action');
            }
            break;
            
        case 'turn_start':
            const currentPlayer = playerInfo.find(p => p.id === actionResult.currentPlayerId);
            if (currentPlayer) {
                addLogEntry(`⏰ 轮到 ${currentPlayer.name} 的回合`, 'turn');
            }
            break;
            
        case 'card_drawn':
            const drawnPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (drawnPlayer && drawnPlayer.id === socket.id) {
                // 自己的抽牌不记录在日志中（因为会显示在手牌中）
            } else if (drawnPlayer) {
                addLogEntry(`🃏 ${drawnPlayer.name} 抽了一张牌`, 'action');
            }
            break;
            
        case 'priest':
            const priestPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            const priestTarget = playerInfo.find(p => p.id === actionResult.targetPlayerId);
            if (priestPlayer && priestTarget) {
                if (priestPlayer.id === socket.id) {
                    // 自己使用牧师时，会在reveal_hand中处理
                } else {
                    addLogEntry(`👁️ ${priestPlayer.name} 使用牧师查看了 ${priestTarget.name} 的手牌`, 'action');
                }
            }
            break;
            
        case 'card_discarded':
            const discardPlayer = playerInfo.find(p => p.id === actionResult.playerId);
            if (discardPlayer) {
                addLogEntry(`🗑️ ${discardPlayer.name} 的 ${actionResult.cardName} 被弃掉（${actionResult.reason}）`, 'info');
            }
            break;
    }
    
    // 渲染日志
    renderGameLog();
}

function addLogEntry(message, type = 'info') {
    const timestamp = new Date().toLocaleTimeString('zh-CN', { 
        hour: '2-digit', 
        minute: '2-digit', 
        second: '2-digit' 
    });
    
    gameLog.push({
        message,
        type,
        timestamp
    });
    
    // 限制日志数量（保留最近50条）
    if (gameLog.length > 50) {
        gameLog.shift();
    }
}

function renderGameLog() {
    const logEl = document.getElementById('game-log');
    if (!logEl) return;
    
    if (gameLog.length === 0) {
        logEl.innerHTML = '<div class="log-empty">游戏日志将在这里显示</div>';
        return;
    }
    
    // 显示最近的日志（从新到旧）
    const recentLogs = gameLog.slice().reverse().slice(0, 20); // 最多显示20条
    
    logEl.innerHTML = recentLogs.map(log => {
        return `
            <div class="log-entry log-${log.type}">
                <span class="log-time">${log.timestamp}</span>
                <span class="log-message">${log.message}</span>
            </div>
        `;
    }).join('');
    
    // 自动滚动到底部（最新日志）
    logEl.scrollTop = 0;
}

function handleGameEnded(data) {
    isGameEnded = true;
    
    const winner = playerInfo.find(p => p.id === data.winner);
    const reason = data.reason;
    
    let message = '';
    let logMessage = '';
    if (reason === 'last_player') {
        message = `🎉 游戏结束！${winner?.name} 获胜！（最后幸存者）`;
        logMessage = `🎉 游戏结束！${winner?.name} 获胜（最后幸存者）`;
    } else if (reason === 'highest_card') {
        const allHands = data.allHands || {};
        let handInfo = Object.entries(allHands)
            .map(([playerId, hand]) => {
                const player = playerInfo.find(p => p.id === playerId);
                const cardName = CARD_INFO[hand[0]]?.name || hand[0];
                return `${player?.name}: ${cardName} (${hand[0]})`;
            })
            .join(', ');
        message = `🎉 游戏结束！牌堆已空，${winner?.name} 的手牌最大！\n所有手牌: ${handInfo}`;
        logMessage = `🎉 游戏结束！牌堆已空，${winner?.name} 的手牌最大获胜`;
    }
    
    updateMessage(message);
    addLogEntry(logMessage, 'system');
    renderGameLog();
    
    // 显示游戏结束弹窗
    setTimeout(() => {
        showGameEndModal(winner, reason, data.allHands);
    }, 1000);
}

let gameEndModalTimer = null; // 保存倒计时定时器引用

function showGameEndModal(winner, reason, allHands) {
    // 先清理可能存在的旧弹窗
    cleanupModals();
    
    // 清除之前的定时器
    if (gameEndModalTimer) {
        clearInterval(gameEndModalTimer);
        gameEndModalTimer = null;
    }
    
    const modal = document.createElement('div');
    modal.className = 'game-end-modal';
    modal.id = 'loveletter-game-end-modal'; // 添加ID以便清理
    
    let content = `
        <div class="modal-content">
            <h2>🎉 游戏结束！</h2>
            <h3>🏆 获胜者: ${winner?.name}</h3>
    `;
    
    if (reason === 'highest_card' && allHands) {
        content += '<div class="final-hands"><h4>最终手牌:</h4><ul>';
        Object.entries(allHands).forEach(([playerId, hand]) => {
            const player = playerInfo.find(p => p.id === playerId);
            const cardName = CARD_INFO[hand[0]]?.name || hand[0];
            content += `<li>${player?.name}: ${cardName} (${hand[0]})</li>`;
        });
        content += '</ul></div>';
    }
    
    content += `
            <button class="modal-button" id="return-room-btn">返回房间 (5)</button>
        </div>
    `;
    
    modal.innerHTML = content;
    document.body.appendChild(modal);
    
    // 倒计时返回
    let countdown = 5;
    const btn = document.getElementById('return-room-btn');
    gameEndModalTimer = setInterval(() => {
        countdown--;
        if (countdown > 0) {
            btn.textContent = `返回房间 (${countdown})`;
        } else {
            clearInterval(gameEndModalTimer);
            gameEndModalTimer = null;
            handleLeaveGame();
        }
    }, 1000);
    
    btn.addEventListener('click', () => {
        if (gameEndModalTimer) {
            clearInterval(gameEndModalTimer);
            gameEndModalTimer = null;
        }
        handleLeaveGame();
    }, { signal: controller.signal });
}

function handleError(data) {
    updateMessage(`❌ 错误: ${data.message}`, 'error');
}

function updateMessage(text, type = 'info') {
    const messageEl = document.getElementById('game-message');
    if (messageEl) {
        messageEl.textContent = text;
        messageEl.className = `message ${type}`;
    }
}

function handleLeaveGame() {
    socket.emit('leave_game', { roomId });
    window.dispatchEvent(new CustomEvent('navigate', {
        detail: { path: `room.html?roomId=${roomId}` }
    }));
}

// 清理模态框
function cleanupModals() {
    // 移除游戏结束弹窗
    const gameEndModal = document.querySelector('#loveletter-game-end-modal, .game-end-modal');
    if (gameEndModal) {
        gameEndModal.remove();
    }
    
    // 移除动作模态框
    const actionModal = document.querySelector('.action-modal');
    if (actionModal) {
        actionModal.remove();
    }
    
    // 移除猜测卡牌模态框
    const guessModal = document.getElementById('card-guess-modal');
    if (guessModal) {
        guessModal.remove();
    }
    
    // 移除弃牌历史模态框
    const discardHistoryModal = document.getElementById('discard-history-modal');
    if (discardHistoryModal) {
        discardHistoryModal.remove();
    }
    
    // 清除定时器
    if (gameEndModalTimer) {
        clearInterval(gameEndModalTimer);
        gameEndModalTimer = null;
    }
}

// 清理函数
export function cleanup() {
    cleanupModals();
    controller?.abort();
    socket?.off('game_state_updated', handleGameStateUpdated);
    socket?.off('your_turn', handleYourTurn);
    socket?.off('action_required', handleActionRequired);
    socket?.off('card_drawn', handleCardDrawn);
    socket?.off('reveal_hand', handleRevealHand);
    socket?.off('game_ended', handleGameEnded);
    socket?.off('error', handleError);
    
    discardPile = [];
    lastHandledDiscards = {};
    isCardDiscardAnimating = false;
    actionSequenceCounter = 0;
    updateDiscardPileView();
    updateDeckInteraction(false);
    updateDiscardInteraction(false);
}
